package com.basker.pisces.orm.session;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.dao.OptimisticLockingFailureException;

import com.basker.pisces.orm.statement.BatchWriteStatement;
import com.basker.pisces.spring.SpringApplicationContext;

class OptimisticLockingValidator {
    static OptimisticLockingValidator INSTANCE = new OptimisticLockingValidator();

    public void checkUpdateCounts(BatchWriteStatement statement, int[] updateCounts) {
        if (!this.enable()) {
            return;
        }

        String sql = statement.getSql();
        if (!this.needCheck(sql)) {
            return;
        }

        List<Integer> failureRows = null;

        for (int i = 0; i < updateCounts.length; i++) {
            int updateCount = updateCounts[i];

            // updateCount表示语句影响的行数，对于乐观锁控制的语句，原则上影响行数非0即1，
            // 但是oracle的批量执行返回值固定为-2，这个后续需要再处理
            if (updateCount == 0) {
                if (failureRows == null) {
                    failureRows = new ArrayList<>(updateCounts.length - i);
                }

                // 记录执行失败的行号
                failureRows.add(i);
            }
        }

        if (failureRows != null) {
            List<List<Object>> arguments = failureRows.stream()
                    .map(i -> Arrays.asList(statement.getBatchArguments().get(i))).collect(Collectors.toList());

            String message = "sql statment update count is 0.sql:" + sql + ",arguments:" + arguments + ".";

            throw new OptimisticLockingFailureException(message);
        }

    }

    private boolean enable() {
        return SpringApplicationContext.getConfig().getBoolean("pisces.orm.optimistic.locking.enable", true);
    }

    private boolean needCheck(String sql) {
        sql = sql.trim();
        return sql.startsWith("UPDATE") || sql.startsWith("update");
    }

}
